import pygame
from PIL import Image
import os
import ctypes
from ctypes import wintypes
import tkinter as tk
from tkinter import messagebox
from tkinter import filedialog
import shutil
import pystray
from PIL import Image as PILImage

# 初始化 Pygame
pygame.init()

# 获取屏幕信息
screen_info = pygame.display.Info()
SCREEN_WIDTH = screen_info.current_w
SCREEN_HEIGHT = screen_info.current_h

# 窗口设置 - 根据 GIF 大小自适应
WINDOW_WIDTH = 200
WINDOW_HEIGHT = 200
FPS = 30

# Windows API 常量
WS_EX_LAYERED = 0x80000
LWA_COLORKEY = 0x1
LWA_ALPHA = 0x2
WS_EX_TRANSPARENT = 0x20
HWND_TOPMOST = -1
SWP_NOMOVE = 0x0002
SWP_NOSIZE = 0x0001
WS_EX_TOOLWINDOW = 0x00000080

# GIF管理全局变量
current_gif_index = 0
gif_files = []
root = None
running = False

# 动画状态
current_frame = 0
last_update = pygame.time.get_ticks()

# 窗口位置 - 默认在右下角
window_x = SCREEN_WIDTH - WINDOW_WIDTH - 50
window_y = SCREEN_HEIGHT - WINDOW_HEIGHT - 50

# 拖拽状态
dragging = False
drag_offset_x = 0
drag_offset_y = 0

# 创建窗口，设置无边框并支持 Alpha
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.NOFRAME)
pygame.display.set_caption("Desktop Pet")

# 设置窗口透明度 - 使用更完整的Windows API
try:
    hwnd = pygame.display.get_wm_info()["window"]
    
    # 获取当前窗口样式
    style = ctypes.windll.user32.GetWindowLongW(hwnd, -20)  # GWL_EXSTYLE
    # 添加分层窗口样式，但不添加透明样式以允许鼠标事件
    style |= WS_EX_LAYERED
    # 新增：添加不在任务栏显示样式
    style |= WS_EX_TOOLWINDOW
    ctypes.windll.user32.SetWindowLongW(hwnd, -20, style)
    
    # 设置窗口透明度 - 使用颜色键透明
    # 将黑色(0,0,0)设为透明色
    ctypes.windll.user32.SetLayeredWindowAttributes(hwnd, 0, 255, LWA_COLORKEY)
    
    # 设置窗口始终置顶
    ctypes.windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
    
    print("成功设置窗口透明度和置顶")
except Exception as e:
    print(f"设置窗口透明度失败: {e}")

# 托盘图标相关函数
def on_quit(icon, item):
    quit_program()

def create_tray_icon():
    try:
        icon_image = PILImage.open("icon.png")
        if getattr(icon_image, "is_animated", False):
            icon_image.seek(0)
        icon_image = icon_image.copy().resize((32, 32))
    except Exception:
        icon_image = PILImage.new("RGBA", (32, 32), (0, 0, 0, 0))
    icon = pystray.Icon("DesktopPet", icon_image, "可爱一二", menu=pystray.Menu(
        pystray.MenuItem("退出", on_quit),
    ))
    icon.run_detached()
    return icon

# 获取gifs目录下的所有GIF文件
def get_gif_files():
    gif_dir = "gifs"
    if not os.path.exists(gif_dir):
        return []
    
    gif_files = []
    for file in os.listdir(gif_dir):
        if file.lower().endswith('.gif'):
            gif_files.append(file)
    
    return sorted(gif_files)

# 批量导入GIF函数
def batch_import_gifs():
    global gif_files, current_gif_index, frames, frame_duration, gif_size
    try:
        root.update()  # 确保菜单弹窗在最前
        file_paths = filedialog.askopenfilenames(
            title="选择要导入的GIF文件",
            filetypes=[("GIF文件", "*.gif")]
        )
        if not file_paths:
            return
        gif_dir = "gifs"
        if not os.path.exists(gif_dir):
            os.makedirs(gif_dir)
        imported = 0
        for file_path in file_paths:
            filename = os.path.basename(file_path)
            dest_path = os.path.join(gif_dir, filename)
            if not os.path.exists(dest_path):
                shutil.copy(file_path, dest_path)
                imported += 1
        gif_files = get_gif_files()
        if imported > 0:
            messagebox.showinfo("导入成功", f"成功导入 {imported} 个GIF文件！")
            # 自动切换到第一个新导入的GIF
            for i, fname in enumerate(gif_files):
                if fname == os.path.basename(file_paths[0]):
                    switch_gif(i)
                    break
        else:
            messagebox.showinfo("提示", "已存在同名文件")
    except Exception as e:
        messagebox.showerror("导入失败", f"导入GIF时出错: {e}")

# 创建右键菜单
def create_context_menu():
    global root, gif_files
    
    # 销毁之前的菜单
    if root:
        root.destroy()
    
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    
    # 创建菜单
    menu = tk.Menu(root, tearoff=0)
    
    # 添加GIF切换子菜单
    if gif_files:
        gif_menu = tk.Menu(menu, tearoff=0)
        for i, gif_file in enumerate(gif_files):
            gif_menu.add_command(
                label=f"{gif_file} {'✓' if i == current_gif_index else ''}",
                command=lambda idx=i: switch_gif(idx)
            )
        menu.add_cascade(label="切换GIF", menu=gif_menu)
    else:
        menu.add_command(label="没有找到GIF文件", state="disabled")
    
    # 添加批量导入GIF菜单项
    menu.add_command(label="批量导入GIF", command=batch_import_gifs)

    menu.add_separator()
    menu.add_command(label="退出程序", command=quit_program)
    
    return menu

# 切换GIF函数
def switch_gif(index):
    global current_gif_index, frames, frame_duration, gif_size
    if 0 <= index < len(gif_files):
        current_gif_index = index
        gif_path = os.path.join("gifs", gif_files[index])
        try:
            frames, frame_duration, gif_size = load_gif_frames(gif_path, WINDOW_WIDTH - 20, WINDOW_HEIGHT - 20)
            print(f"成功切换到: {gif_files[index]}")
        except Exception as e:
            print(f"切换GIF失败: {e}")

# 退出程序函数
def quit_program():
    global running
    running = False
    if root:
        root.destroy()
    pygame.quit()
    os._exit(0)  # 立即终止整个进程，防止主循环继续

# 加载 GIF 动画并自适应大小
def load_gif_frames(gif_path, target_width, target_height):
    if not os.path.exists(gif_path):
        raise FileNotFoundError(f"GIF file {gif_path} not found")
    
    print(f"正在加载 GIF 文件: {gif_path}")
    gif = Image.open(gif_path)
    frames = []
    
    # 计算缩放比例，保持宽高比
    original_width, original_height = gif.size
    scale_x = target_width / original_width
    scale_y = target_height / original_height
    scale = min(scale_x, scale_y)
    
    new_width = int(original_width * scale)
    new_height = int(original_height * scale)
    
    print(f"原始尺寸: {original_width}x{original_height}")
    print(f"缩放后尺寸: {new_width}x{new_height}")
    
    try:
        frame_count = 0
        while True:
            # 确保帧支持透明度
            frame = gif.copy().convert('RGBA')  # 转换为 RGBA 模式以保留透明信息
            
            # 处理透明像素 - 将纯黑色像素转换为透明
            frame_data = frame.getdata()
            new_data = []
            for item in frame_data:
                # 如果像素是纯黑色或接近黑色，将其设为透明
                if item[0] < 10 and item[1] < 10 and item[2] < 10:
                    new_data.append((0, 0, 0, 0))  # 完全透明
                else:
                    new_data.append(item)
            
            frame.putdata(new_data)
            frame = frame.resize((new_width, new_height), Image.Resampling.LANCZOS)

            # 将 PIL 图像转换为 Pygame 表面
            mode = frame.mode
            size = frame.size
            data = frame.tobytes()
            pygame_image = pygame.image.fromstring(data, size, mode)

            # 确保表面支持 Alpha 通道
            pygame_image = pygame_image.convert_alpha()
            frames.append(pygame_image)
            frame_count += 1
            gif.seek(gif.tell() + 1)
    except EOFError:
        pass
    
    duration = gif.info.get('duration', 100) / 1000  # 转换为秒
    print(f"成功加载 {frame_count} 帧，每帧持续时间: {duration}秒")
    return frames, duration, (new_width, new_height)

def main():
    global current_frame, last_update, window_x, window_y, dragging, drag_offset_x, drag_offset_y, running, gif_files, frames, frame_duration, gif_size
    # 新增：创建托盘图标
    tray_icon = create_tray_icon()
    running = True
    clock = pygame.time.Clock()

    # 加载 GIF 文件，从 gifs 目录
    gif_files = get_gif_files()
    if not gif_files:
        print("在gifs目录中没有找到GIF文件")
        print("程序退出")
        exit(1)

    gif_path = os.path.join("gifs", gif_files[current_gif_index])
    try:
        frames, frame_duration, gif_size = load_gif_frames(gif_path, WINDOW_WIDTH - 20, WINDOW_HEIGHT - 20)
        print(f"成功加载 GIF 文件: {gif_path}")
    except FileNotFoundError:
        print(f"GIF 文件未找到: {gif_path}")
        print("程序退出")
        exit(1)
    except Exception as e:
        print(f"加载 GIF 时出错: {e}")
        print("程序退出")
        exit(1)

    # 动画状态初始化
    current_frame = 0
    last_update = pygame.time.get_ticks()

    # 设置窗口初始位置
    try:
        import ctypes
        hwnd = pygame.display.get_wm_info()["window"]
        ctypes.windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, window_x, window_y, 0, 0, 0x0001)
    except:
        os.environ['SDL_VIDEO_WINDOW_POS'] = f"{window_x},{window_y}"
        pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.NOFRAME | pygame.SRCALPHA)

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:  # 左键点击
                    dragging = True
                    mouse_x, mouse_y = pygame.mouse.get_pos()
                    drag_offset_x = mouse_x
                    drag_offset_y = mouse_y
                    print(f"开始拖拽 - 鼠标位置: ({mouse_x}, {mouse_y})")
                elif event.button == 3:  # 右键点击
                    # 显示右键菜单
                    try:
                        menu = create_context_menu()
                        # 获取鼠标在屏幕上的绝对位置
                        cursor = ctypes.wintypes.POINT()
                        ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
                        menu.post(cursor.x, cursor.y)
                        root.update()
                    except Exception as e:
                        print(f"显示菜单失败: {e}")
            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:  # 左键释放
                    dragging = False
                    print("结束拖拽")
            elif event.type == pygame.MOUSEMOTION:
                if dragging:
                    mouse_x, mouse_y = pygame.mouse.get_pos()
                    new_x = window_x + mouse_x - drag_offset_x
                    new_y = window_y + mouse_y - drag_offset_y

                    new_x = max(0, min(new_x, SCREEN_WIDTH - WINDOW_WIDTH))
                    new_y = max(0, min(new_y, SCREEN_HEIGHT - WINDOW_HEIGHT))

                    window_x = new_x
                    window_y = new_y

                    try:
                        import ctypes
                        hwnd = pygame.display.get_wm_info()["window"]
                        ctypes.windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, window_x, window_y, 0, 0, 0x0001)
                    except:
                        os.environ['SDL_VIDEO_WINDOW_POS'] = f"{window_x},{window_y}"
                        pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.NOFRAME | pygame.SRCALPHA)

        # 更新动画帧
        current_time = pygame.time.get_ticks()
        if current_time - last_update > frame_duration * 1000:
            current_frame = (current_frame + 1) % len(frames)
            last_update = current_time

        # 绘制 - 使用透明背景
        screen.fill((0, 0, 0, 0))  # 完全透明背景

        # 计算居中位置
        center_x = (WINDOW_WIDTH - gif_size[0]) // 2
        center_y = (WINDOW_HEIGHT - gif_size[1]) // 2

        screen.blit(frames[current_frame], (center_x, center_y))
        pygame.display.flip()

        clock.tick(FPS)

    # 清理资源
    if root:
        root.destroy()
    pygame.quit()


if __name__ == "__main__":
    main()